package utils

import (
	"fmt"
	"fpga-vboard/config"
	"fpga-vboard/logger"
	"io"
	"os"
	"os/exec"
)

type RunProc struct {
	// 命令
	Cmd *exec.Cmd
	// 标准输入
	Stdin io.WriteCloser
	// 标准输出
	Stdout io.ReadCloser
	// 标准错误输出
	Stderr io.ReadCloser
}

func NewRunProc(cmd string, args []string, envs []string, dir string) *RunProc {
	c := exec.Command(cmd, args...)
	c.Dir = dir
	c.Env = os.Environ()
	c.Env = append(c.Env, envs...)
	return &RunProc{
		Cmd: c,
	}
}

func (rp *RunProc) Run() error {
	var err error
	rp.Stdin, err = rp.Cmd.StdinPipe()
	if err != nil {
		logger.ErrorLog("get stdinPipe error: %v", err)
		return err
	}
	rp.Stdout, err = rp.Cmd.StdoutPipe()
	if err != nil {
		logger.ErrorLog("get stdoutPipe error: %v", err)
		return err
	}
	rp.Stderr, err = rp.Cmd.StderrPipe()
	if err != nil {
		logger.ErrorLog("get stderrPipe error: %v", err)
		return err
	}
	err = rp.Cmd.Start()
	if err != nil {
		logger.ErrorLog("run cmd error: %v", err)
		return err
	}
	return nil
}

func (rp *RunProc) IsRunning() bool {
	return rp.Cmd == nil || rp.Cmd.ProcessState == nil || !rp.Cmd.ProcessState.Exited()
}

func (rp *RunProc) SendByte(b byte) error {
	if !rp.IsRunning() {
		logger.ErrorLog("cmd is not running")
		return fmt.Errorf("cmd is not running")
	}
	_, err := rp.Stdin.Write([]byte{b})
	if err != nil {
		logger.ErrorLog("send byte error: %v", err)
		return err
	}
	return nil
}

func (rp *RunProc) SendString(str string) error {
	if !rp.IsRunning() {
		logger.ErrorLog("cmd is not running")
		return fmt.Errorf("cmd is not running")
	}
	_, err := rp.Stdin.Write([]byte(str))
	if err != nil {
		logger.ErrorLog("send string error: %v", err)
		return err
	}
	return nil
}

func (rp *RunProc) Kill() error {
	err := rp.Cmd.Process.Kill()
	if err != nil {
		logger.ErrorLog("kill cmd error: %v", err)
		return err
	}
	return nil
}

func (rp *RunProc) Wait() error {
	err := rp.Cmd.Wait()
	if err != nil {
		logger.ErrorLog("wait cmd error: %v", err)
		return err
	}
	return nil
}

func StartSerialDisplay() (*RunProc, error) {
	proc := NewRunProc(config.AppCfg.ExecutablePath, []string{"-r", "uartterm"}, []string{`devserver=127.0.0.1:18899`}, config.AppCfg.AppPath)
	return proc, proc.Run()
}
